[Chapter Fifteen][Previous]
[Art of Assembly][Randall
Hyde]
Art of Assembly: Chapter Fifteen
- 15.7 - Sample Programs
- 15.7.1 - Find.asm
- 15.7.2 - StrDemo.asm
- 15.7.3 - Fcmp.asm
15.7 Sample Programs
In this section there are three sample programs. The first searches
through a file for a particular string and displays the line numbers of
any lines containing that string. This program demonstrates the use of the
strstr
function (among other things). The second program is
a demo program that uses several of the string functions available in the
UCR Standard Library's string package. The third program demonstrates how
to use the 80x86 cmps
instruction to compare the data in two
files. These programs (find.asm, strdemo.asm, and fcmp.asm) are available
on the companion CD-ROM.
15.7.1 Find.asm
; Find.asm
;
; This program opens a file specified on the command line and searches for
; a string (also specified on the command line).
;
; Program Usage:
;
; find "string" filename
.xlist
include stdlib.a
includelib stdlib.lib
.list
wp textequ <word ptr>
dseg segment para public 'data'
StrPtr dword ?
FileName dword ?
LineCnt dword ?
FVar filevar {}
InputLine byte 1024 dup (?)
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
; Readln- This procedure reads a line of text from the input
; file and buffers it up in the "InputLine" array.
ReadLn proc
push es
push ax
push di
push bx
lesi FVar ;Read from our file.
mov bx, 0 ;Index into InputLine.
ReadLp: fgetc ;Get next char from file.
jc EndRead ;Quit on EOF
cmp al, cr ;Ignore carriage returns.
je ReadLp
cmp al, lf ;End of line on line feed.
je EndRead
mov InputLine[bx], al
inc bx
jmp ReadLp
; If we hit the end of a line or the end of the file,
; zero-terminate the string.
EndRead: mov InputLine[bx], 0
pop bx
pop di
pop ax
pop es
ret
ReadLn endp
; The following main program extracts the search string and the
; filename from the command line, opens the file, and then searches
; for the string in that file.
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
meminit
argc
cmp cx, 2
je GoodArgs
print
byte "Usage: find 'string' filename",cr,lf,0
jmp Quit
GoodArgs: mov ax, 1 ;Get the string to search for
argv ; off the command line.
mov wp StrPtr, di
mov wp StrPtr+2, es
mov ax, 2 ;Get the filename from the
argv ; command line.
mov wp Filename, di
mov wp Filename+2, es
; Open the input file for reading
mov ax, 0 ;Open for read.
mov si, wp FileName
mov dx, wp FileName+2
lesi Fvar
fopen
jc BadOpen
; Okay, start searching for the string in the file.
mov wp LineCnt, 0
mov wp LineCnt+2, 0
SearchLp: call ReadLn
jc AtEOF
; Bump the line number up by one. Note that this is 8086 code
; so we have to use extended precision arithmetic to do a 32-bit
; add. LineCnt is a 32-bit variable because some files have more
; that 65,536 lines.
add wp LineCnt, 1
adc wp LineCnt+2, 0
; Search for the user-specified string on the current line.
lesi InputLine
mov dx, wp StrPtr+2
mov si, wp StrPtr
strstr
jc SearchLp ;Jump if not found.
; Print an appropriate message if we found the string.
printf
byte "Found '%^s' at line %ld\n",0
dword StrPtr, LineCnt
jmp SearchLp
; Close the file when we're done.
AtEOF: lesi FVar
fclose
jmp Quit
BadOpen: printf
byte "Error attempting to open %^s\n",cr,lf,0
dword FileName
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk db 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
15.7.2 StrDemo.asm
This short demo program just shows off how to use several of the string
routines found in the UCR Standard Library strings package.
; StrDemo.asm- Demonstration of some of the various UCR Standard Library
; string routines.
include stdlib.a
includelib stdlib.lib
dseg segment para public 'data'
MemAvail dw ?
String byte 256 dup (0)
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
Main proc
mov ax, seg dseg ;Set up the segment registers
mov ds, ax
mov es, ax
MemInit
mov MemAvail, cx
printf
db "There are %x paragraphs of memory available."
db cr,lf,lf,0
dd MemAvail
; Demonstration of StrTrim:
print
db "Testing strtrim on 'Hello there '",cr,lf,0
strdupl
HelloThere1 db "Hello there ",0
strtrim
mov al, "'"
putc
puts
putc
putcr
free
;Demonstration of StrTrimm:
print
db "Testing strtrimm on 'Hello there '",cr,lf,0
lesi HelloThere1
strtrimm
mov al, "'"
putc
puts
putc
putcr
free
; Demonstration of StrBdel
print
db "Testing strbdel on ' Hello there '",cr,lf,0
strdupl
HelloThere3 db " Hello there ",0
strbdel
mov al, "'"
putc
puts
putc
putcr
free
; Demonstration of StrBdelm
print
db "Testing strbdelm on ' Hello there '",cr,lf,0
lesi HelloThere3
strbdelm
mov al, "'"
putc
puts
putc
putcr
free
; Demonstrate StrCpyl:
ldxi string
strcpyl
byte "Copy this string to the 'String' variable",0
printf
byte "STRING = '%s'",cr,lf,0
dword String
; Demonstrate StrCatl:
lesi String
strcatl
byte ". Put at end of 'String'",0
printf
byte "STRING = ",'"%s"',cr,lf,0
dword String
; Demonstrate StrChr:
lesi String
mov al, "'"
strchr
print
byte "StrChr: First occurrence of ", '"', "'"
byte '" found at position ',0
mov ax, cx
puti
putcr
; Demonstrate StrStrl:
lesi String
strstrl
byte "String",0
print
byte 'StrStr: First occurrence of "String" found at position ',0
mov ax, cx
puti
putcr
; Demo of StrSet
lesi String
mov al, '*'
strset
printf
byte "Strset: '%s'",cr,lf,0
dword String
; Demo of strlen
lesi String
strlen
print
byte "String length = ",0
puti
putcr
Quit: mov ah, 4ch
int 21h
Main endp
cseg ends
; Allocate a reasonable amount of space for the stack (2k).
sseg segment para stack 'stack'
stk db 256 dup ("stack ")
sseg ends
; zzzzzzseg must be the last segment that gets loaded into memory!
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
heap db 1024 dup (?)
zzzzzzseg ends
end Main
15.7.3 Fcmp.asm
This is a file comparison program. It demonstrates the use of the 80x86
cmps instruction (as well as blocked I/O under DOS).
; FCMP.ASM- A file comparison program that demonstrates the use
; of the 80x86 string instructions.
.xlist
include stdlib.a
includelib stdlib.lib
.list
dseg segment para public 'data'
Name1 dword ? ;Ptr to filename #1
Name2 dword ? ;Ptr to filename #2
Handle1 word ? ;File handle for file #1
Handle2 word ? ;File handle for file #2
LineCnt word 0 ;# of lines in the file.
Buffer1 db 256 dup (0) ;Block of data from file 1
Buffer2 db 256 dup (0) ;Block of data from file 2
dseg ends
wp equ <word ptr>
cseg segment para public 'code'
assume cs:cseg, ds:dseg
; Error- Prints a DOS error message depending upon the error type.
Error proc near
cmp ax, 2
jne NotFNF
print
db "File not found",0
jmp ErrorDone
NotFNF: cmp ax, 4
jne NotTMF
print
db "Too many open files",0
jmp ErrorDone
NotTMF: cmp ax, 5
jne NotAD
print
db "Access denied",0
jmp ErrorDone
NotAD: cmp ax, 12
jne NotIA
print
db "Invalid access",0
jmp ErrorDone
NotIA:
ErrorDone: putcr
ret
Error endp
; Okay, here's the main program. It opens two files, compares them, and
; complains if they're different.
Main proc
mov ax, seg dseg ;Set up the segment registers
mov ds, ax
mov es, ax
meminit
; File comparison routine. First, open the two source files.
argc
cmp cx, 2 ;Do we have two filenames?
je GotTwoNames
print
db "Usage: fcmp file1 file2",cr,lf,0
jmp Quit
GotTwoNames: mov ax, 1 ;Get first file name
argv
mov wp Name1, di
mov wp Name1+2, es
; Open the files by calling DOS.
mov ax, 3d00h ;Open for reading
lds dx, Name1
int 21h
jnc GoodOpen1
printf
db "Error opening %^s:",0
dd Name1
call Error
jmp Quit
GoodOpen1: mov dx, dseg
mov ds, dx
mov Handle1, ax
mov ax, 2 ;Get second file name
argv
mov wp Name2, di
mov wp Name2+2, es
mov ax, 3d00h ;Open for reading
lds dx, Name2
int 21h
jnc GoodOpen2
printf
db "Error opening %^s:",0
dd Name2
call Error
jmp Quit
GoodOpen2: mov dx, dseg
mov ds, dx
mov Handle2, ax
; Read the data from the files using blocked I/O
; and compare it.
mov LineCnt, 1
CmpLoop: mov bx, Handle1 ;Read 256 bytes from
mov cx, 256 ; the first file into
lea dx, Buffer1 ; Buffer1.
mov ah, 3fh
int 21h
jc FileError
cmp ax, 256 ;Leave if at EOF.
jne EndOfFile
mov bx, Handle2 ;Read 256 bytes from
mov cx, 256 ; the second file into
lea dx, Buffer2 ; Buffer2
mov ah, 3fh
int 21h
jc FileError
cmp ax, 256 ;If we didn't read 256 bytes,
jne BadLen ; the files are different.
; Okay, we've just read 256 bytes from each file, compare the buffers
; to see if the data is the same in both files.
mov ax, dseg
mov ds, ax
mov es, ax
mov cx, 256
lea di, Buffer1
lea si, Buffer2
cld
repe cmpsb
jne BadCmp
jmp CmpLoop
FileError: print
db "Error reading files: ",0
call Error
jmp Quit
BadLen: print
db "File lengths were different",cr,lf,0
BadCmp: print
db 7,"Files were not equal",cr,lf,0
mov ax, 4c01h ;Exit with error.
int 21h
; If we reach the end of the first file, compare any remaining bytes
; in that first file against the remaining bytes in the second file.
EndOfFile: push ax ;Save final length.
mov bx, Handle2
mov cx, 256
lea dx, Buffer2
mov ah, 3fh
int 21h
jc BadCmp
pop bx ;Retrieve file1's length.
cmp ax, bx ;See if file2 matches it.
jne BadLen
mov cx, ax ;Compare the remaining
mov ax, dseg ; bytes down here.
mov ds, ax
mov es, ax
lea di, Buffer2
lea si, Buffer1
repe cmpsb
jne BadCmp
Quit: mov ax, 4c00h ;Set Exit code to okay.
int 21h
Main endp
cseg ends
; Allocate a reasonable amount of space for the stack (2k).
sseg segment para stack 'stack'
stk db 256 dup ("stack ")
sseg ends
; zzzzzzseg must be the last segment that gets loaded into memory!
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
- 15.7 - Sample Programs
- 15.7.1 - Find.asm
- 15.7.2 - StrDemo.asm
- 15.7.3 - Fcmp.asm
Art of Assembly: Chapter Fifteen - 28 SEP 1996
[Chapter Fifteen][Previous]
[Art of Assembly][Randall
Hyde]